iT邦幫忙

2025 iThome 鐵人賽

DAY 8
0

在前一篇文章中,我們介紹了怎麼在 Effect 中處理錯誤,然而,目前我們拋出的錯誤型態只有 Error ,說好的一看 type 就能知道會發生什麼錯誤呢?在這篇文章中,我們要看 Effect 中的第一個資料型態的函式庫,並用它來建立自訂的錯誤類型

在開始之前,我們先來看看一般要建立自訂的錯誤類型要怎麼做,這在 MDN 其實就有個範例

class MyError extends Error {
  // 這邊是原本 Error 傳入的參數,你也可以傳入自訂的參數來擴充自訂的 error 的屬性
  // 但不論如何,都還是建議要可以傳入 ErrorOptions 中的 cause ,以連結到原始的錯誤
  constructor(message: string, options: ErrorOptions) {
    // 呼叫 super 初始化
    super(message, options)
    this.name = 'MyError' // 設定 error 的名稱
    if (Error.captureStackTrace) {
      // 確保 error 的 constructor 本身不會出現在 stack trace
      Error.captureStackTrace(this, MyError);
    }
    
    // 你可以設定其它屬性以提供更多的資訊
  }
}

說簡單也不簡單,複雜到也還好,但… 如果每個自訂的 error 都要寫一次這些其實有點麻煩

使用 Data.Error 來建立 error

在 Effect 中,你可以使用 Data.Error 或是 Data.TaggedError 來建立 error ,就像這樣

import { Data } from 'effect'
// 我們可以在 Data.Error 的 generic 參數中設定這個 error 要接受哪些屬性
// 推薦加上 `cause`
class ValidationError extends Data.Error<{message: string, data?: unknown, cause?: unknown}> {}

就這樣,恭喜你有個自訂的 error 了,使用時就像這樣

new ValidationError({
  message: 'input validation fail',
  data: { userInput: 'invalid data' },
  cause: new Error('your original error'),
})

如果搭配 Effect.try 大概會是這種感覺

// 假設我們用 zod 來驗證資料
import { z } from 'zod'

const dataSchema = z.object({ data: z.string() })

Effect.try({
  try: () => dataSchema.parse(userData),
  catch: (error) => new ValidationError({
    message: 'input validation fail',
    data: userData,
    cause: error,
  })
})

使用 Data.TaggedErrorEffect.catchTag*

在 Data 中,還有一個 TaggedError ,用法也很類似

// 差別在於這邊要傳入一個 error 的名字
class ValidationError extends Data.TaggedError('ValidationError')<{
  message: string
  data?: unknown
  cause?: unknown
}> {}

這個跟 Data.Error 的差別是,建出來的 error 會多一個 _tag 的屬性,屬性會是你設定的名字 ValidationError ,這在 Effect 中是一種很常見的 pattern ,我們可以使用 Effect.catchTag 或是 Effect.catchTags 來捕捉帶有特定的 _tag 的錯誤

pipe(
  Effect.fail(new ValidationError({ message: 'error' })),
  Effect.catchTag('ValidationError', (error) => {
    console.error(error)
    return Effect.void
  }),
)

// 或是使用 catchTags 一次處理多個 error
pipe(
  Effect.fail(new ValidationError({ message: 'error' })),
  Effect.catchTags({
    ValidationError: (error) => {
      console.error(error)
      return Effect.void
    },
  }),
)

這邊我們真正的認識了 Effect 中的一個資料型態,雖然之前也有出現過一個 Either 不過並沒有很完整的介紹,其實 Data 的功能還不只這樣,有機會之後再來介紹,下一次我們來看一個實際的 Effect 的使用案例

Reference


上一篇
6. Effect 中的錯誤
下一篇
8. Effect 實戰分享 1 :資料清理
系列文
Effect 魔法:打造堅不可摧的應用程式12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言